package com.atguigu.gmall.seckill.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.enums.OrderStatus;
import com.atguigu.gmall.enums.PaymentWay;
import com.atguigu.gmall.enums.ProcessStatus;
import com.atguigu.gmall.mq.seckill.SeckillOrderMsg;
import com.atguigu.gmall.order.entity.OrderDetail;
import com.atguigu.gmall.order.entity.OrderInfo;
import com.atguigu.gmall.seckill.entity.SeckillGoods;
import com.atguigu.gmall.seckill.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.seckill.service.SeckillGoodsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
* @author 10574
* @description 针对表【seckill_goods】的数据库操作Service实现
* @createDate 2022-12-28 01:06:23
*/
@Slf4j
@Service
public class SeckillGoodsServiceImpl extends ServiceImpl<SeckillGoodsMapper, SeckillGoods>
    implements SeckillGoodsService{

    @Autowired
    StringRedisTemplate redisTemplate;

    Map<Long,SeckillGoods> localCache=new ConcurrentHashMap<>();

    @Override
    public List<SeckillGoods> getSeckillGoodsByDay(String date) {
        return baseMapper.getSeckillGoodsByDay(date);
    }

    @Override
    public List<SeckillGoods> getSeckillGoodsByDayFromCache(String date) {

        ////如果有了多级缓存；先查询离自己最近的缓存 先查询本地缓存
        List<SeckillGoods> caches = localCache.values().stream()
                .sorted(Comparator.comparing(SeckillGoods::getStartTime))
                .collect(Collectors.toList());
        if (caches==null||caches.size()==0){
            log.info("本地缓存没有命中。。。");
            String cacheKey= RedisConst.SECKILL_GOODS_CACHE+date;
            //查询缓存
            List<Object> values = redisTemplate.opsForHash().values(cacheKey);

            List<SeckillGoods> seckillGoods = values.stream()
                    .map(item -> item.toString())
                    .map(item -> JSON.parseObject(item, SeckillGoods.class))
                    .sorted((Comparator.comparing(SeckillGoods::getStartTime)))
                    .collect(Collectors.toList());
            //存入本地缓存
            saveToLocalCache(seckillGoods);
            return seckillGoods;
        }
        log.info("本地缓存命中。。。");
        return caches;
    }

    @Override
    public void saveToLocalCache(List<SeckillGoods> seckillGoods) {
        for (SeckillGoods seckillGood : seckillGoods) {
            localCache.put(seckillGood.getSkuId(),seckillGood);
        }
    }

    @Override
    public SeckillGoods getDetail(Long skuId) {
        SeckillGoods seckillGoods = localCache.get(skuId);
        if (seckillGoods!=null){
            log.info("本地命中");
            return seckillGoods;
        }
        getSeckillGoodsByDayFromCache(DateUtil.formatDate(new Date()));
        seckillGoods = localCache.get(skuId);
        return seckillGoods;
    }

    @Override
    public void deduceStock(Long id) {
        SeckillGoods seckillGoods = this.getById(id);
        seckillGoods.setStockCount(seckillGoods.getStockCount()-1);
        this.save(seckillGoods);
    }

    @Override
    public void saveSeckillOrder(SeckillOrderMsg orderMsg) {

        //获取秒杀商品详情
        SeckillGoods detail = getDetail(orderMsg.getSkuId());
        OrderInfo info = new OrderInfo();
        info.setTotalAmount(detail.getCostPrice());
        info.setOrderStatus(OrderStatus.UNPAID.name());
        info.setUserId(orderMsg.getUserId());
        info.setPaymentWay(PaymentWay.ONLINE.name());
        info.setOutTradeNo("ATGUIGU-"+System.currentTimeMillis()+"-"+orderMsg.getUserId());
        info.setTradeBody(detail.getSkuName());
        info.setCreateTime(new Date());
        info.setExpireTime(new Date(System.currentTimeMillis()+1000*60*30L));
        info.setProcessStatus(ProcessStatus.UNPAID.name());
        info.setParentOrderId(0L);
        info.setImgUrl(detail.getSkuDefaultImg());

        info.setOperateTime(new Date());
        info.setActivityReduceAmount(new BigDecimal("0"));
        //设置秒杀优惠减的金额
        info.setCouponAmount(detail.getPrice().subtract(detail.getCostPrice()));
        info.setOriginalTotalAmount(detail.getCostPrice());
        info.setFeightFee(new BigDecimal("0"));
        List<OrderDetail> details=new ArrayList<>();
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setUserId(orderMsg.getUserId());
        orderDetail.setSkuId(orderMsg.getSkuId());
        orderDetail.setSkuName(detail.getSkuName());
        orderDetail.setImgUrl(detail.getSkuDefaultImg());
        orderDetail.setOrderPrice(detail.getCostPrice());
        orderDetail.setSkuNum(1);
        orderDetail.setCreateTime(new Date());
        orderDetail.setSplitTotalAmount(detail.getCostPrice());
        orderDetail.setSplitActivityAmount(new BigDecimal("0"));
        orderDetail.setSplitCouponAmount(detail.getPrice().subtract(detail.getCostPrice()));

        details.add(orderDetail);
        info.setOrderDetails(details);
        info.setWareId(0L);

        //seckill:order:秒杀码
        redisTemplate.opsForValue().set(RedisConst.SECKILL_ORDER+orderMsg.getCode(),
                JSON.toJSONString(info),2, TimeUnit.DAYS);
    }

    @Override
    public void updateRedisStock(SeckillOrderMsg orderMsg) {
        Object obj = redisTemplate.opsForHash().get(RedisConst.SECKILL_GOODS_CACHE + orderMsg.getDate(),
                orderMsg.getSkuId().toString());
        if (StringUtils.isEmpty(obj)){
            return;
        }
        SeckillGoods seckillGoods = JSON.parseObject(obj.toString(), SeckillGoods.class);
        seckillGoods.setStockCount(seckillGoods.getStockCount()-1);
        //保存redis
        redisTemplate.opsForHash().put(RedisConst.SECKILL_GOODS_CACHE + orderMsg.getDate(),
                orderMsg.getSkuId().toString(),JSON.toJSONString(seckillGoods));
    }
}




